package com.ruoyi.zhgd.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.ruoyi.common.utils.StringUtils;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.zhgd.domain.*;
import com.ruoyi.zhgd.service.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.zhgd.domain.bo.ZjExperimentBindingBo;
import com.ruoyi.zhgd.domain.vo.ZjExperimentBindingVo;
import com.ruoyi.zhgd.mapper.ZjExperimentBindingMapper;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 试验数据绑定Service业务层处理
 *
 * @author cj
 * @date 2023-10-20
 */
@RequiredArgsConstructor
@Service
@DS("sjcj")
public class ZjExperimentBindingServiceImpl implements IZjExperimentBindingService {

    @Autowired
    private INLaboratoryAsphaltRequiresRefService requiresRefService;

    @Autowired
    private INLaboratoryAsphaltLowTemperatureElongationResService elongationResService;

    @Autowired
    private INLaboratoryAsphaltPenetrometerResService penetrometerResService;

    @Autowired
    private INLaboratoryAsphaltSofteningPointResService softeningPointResService;

    @Autowired
    private INLaboratoryMarshallRequiresService inLaboratoryMarshallRequiresService;

    @Autowired
    private INLaboratoryMarshallStabilityNewResService inLaboratoryMarshallStabilityNewResService;

    @Autowired
    private INLaboratoryAsphaltCombustionFurnaceResService inLaboratoryAsphaltCombustionFurnaceResService;

    @Autowired
    private IZjNWarningUsingService usingService;

    private final ZjExperimentBindingMapper baseMapper;
    @Autowired
    private IZjNWarningUserMessageService messageService;

    /**
     * 查询试验数据绑定
     */
    @Override
    public ZjExperimentBindingVo queryById(String id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询试验数据绑定列表
     */
    @Override
    public TableDataInfo<ZjExperimentBindingVo> queryPageList(ZjExperimentBindingBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<ZjExperimentBinding> lqw = buildQueryWrapper(bo);
        Page<ZjExperimentBindingVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询试验数据绑定列表
     */
    @Override
    public List<ZjExperimentBindingVo> queryList(ZjExperimentBindingBo bo) {
        LambdaQueryWrapper<ZjExperimentBinding> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<ZjExperimentBinding> buildQueryWrapper(ZjExperimentBindingBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<ZjExperimentBinding> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getLaboratoryId()), ZjExperimentBinding::getLaboratoryId, bo.getLaboratoryId());
        lqw.eq(bo.getAsphaltVarietyId() != null, ZjExperimentBinding::getAsphaltVarietyId, bo.getAsphaltVarietyId());
        lqw.eq(bo.getAsphaltLabel() != null, ZjExperimentBinding::getAsphaltLabel, bo.getAsphaltLabel());
        lqw.eq(bo.getTestNum() != null, ZjExperimentBinding::getTestNum, bo.getTestNum());
        lqw.eq(StringUtils.isNotBlank(bo.getTestType()), ZjExperimentBinding::getTestType, bo.getTestType());
        lqw.eq(bo.getCreateDate() != null, ZjExperimentBinding::getCreateDate, bo.getCreateDate());
        return lqw;
    }

    /**
     * 新增试验数据绑定
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertByBo(ZjExperimentBindingBo bo) {
        //设置试验编号和时间
        bo.setCreateDate(new Date());
        Long testNum = baseMapper.selectMaxTestNum();
        if (testNum != null && testNum > 0) {
            testNum = testNum + 1;
        }else{
            testNum = Long.valueOf(1);
        }
        // 设置试验技术类型id
        if (ObjectUtils.isNotEmpty(bo.getTestTypeId())) {
            bo.setLaboratoryId(bo.getTestTypeId());
        }
        //技术要求
        List<NLaboratoryAsphaltRequiresRef> requiresRef = new ArrayList<>();
        //关联的试验数据类型， 1延度 2软化点 3针入度 4燃烧炉 5马歇尔
        if (bo.getType() == 1) {
            String type = "YD";
            List<NLaboratoryAsphaltLowTemperatureElongationRes> laboratoryAsphalt = elongationResService.selectElongationRes(bo.getIds());
            requiresRef = getRequiresRefYd(bo.getTestType(),type);
            estimateYdQualified(requiresRef,laboratoryAsphalt,bo);
        } else if (bo.getType() == 2) {
            String type = "RHD";
            requiresRef = getRequiresRef(bo.getTestType(),type);
            List<NLaboratoryAsphaltSofteningPointRes> softeningPointRes = softeningPointResService.selectSofteningPoint(bo.getIds());
            estimateRhdQualified(requiresRef,softeningPointRes,bo);
        } else if (bo.getType() == 3) {
            String type = "ZRD";
            requiresRef = getRequiresRef(bo.getTestType(),type);
            List<NLaboratoryAsphaltPenetrometerRes> penetrometerRes = penetrometerResService.selectPenetrometer(bo.getIds());
            estimateZrdQualified(requiresRef,penetrometerRes,bo);
        } else if (bo.getType() == 4) { // 暂时无技术要求指标
            // @TODO 待燃烧炉技术要求参数确定
        } else if (bo.getType() == 5) {
            // 根据试验ids查询实验数据列表
            List<NLaboratoryMarshallStabilityNewRes> marshallStabilityNewRes = inLaboratoryMarshallStabilityNewResService.getListByIds(bo.getIds());
            // 获取技术要求指标
            NLaboratoryMarshallRequires marshallRequires = getMarshallRequires(bo);
            // 根据技术要求判断是否合格并更新
            estimateMarshallQualified(marshallStabilityNewRes, marshallRequires, bo);
        }
        //保存关联数据
        bo.setTestNum(testNum);
        saveZjExperimentBindingBo(bo);
    }

    //保存
    @Transactional(rollbackFor = Exception.class)
    public void saveZjExperimentBindingBo(ZjExperimentBindingBo bo) {
        int size1 = bo.getIds().size();
        int size2 = bo.getRemarks().size();
        int size3 = bo.getBoMessage().size();
        int maxSize = Math.max(size1,size2);
        for (int i = 0; i < maxSize; i++) {
            bo.setLaboratoryId((i < size1 ? bo.getIds().get(i) : null));
            bo.setRemark(i < size2 ? bo.getRemarks().get(i) : null);
            bo.setMessage(i < size3 ? bo.getBoMessage().get(i) : null);
            ZjExperimentBinding z = new ZjExperimentBinding();
            BeanUtils.copyProperties(bo,z);
            baseMapper.insert(z);
        }

    }


    //延度
    private void estimateYdQualified(List<NLaboratoryAsphaltRequiresRef> requiresRef, List<NLaboratoryAsphaltLowTemperatureElongationRes> laboratoryAsphalt, ZjExperimentBindingBo bo) {
        List<String> list = new ArrayList<>();
        List<String> boMessage = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            for (int i = 0; i < laboratoryAsphalt.size(); i++) {
                Integer eligible = 0;
                for (int y = 0; y < requiresRef.size(); y++) {
                    //判断设定温度  延度技术要求温度上限用的temperature
                    if (requiresRef.get(y).getMin().compareTo(laboratoryAsphalt.get(i).getSetTemp()) <1 && laboratoryAsphalt.get(i).getSetTemp().compareTo(requiresRef.get(y).getTemperature()) <1) {
                        if (requiresRef.get(y).getMin().compareTo(laboratoryAsphalt.get(i).getCurrTemp()) <1 && laboratoryAsphalt.get(i).getCurrTemp().compareTo(requiresRef.get(y).getTemperature()) <1) {
                            if (requiresRef.get(y).getYdMin().compareTo(laboratoryAsphalt.get(i).getLength1()) < 1 &&
                                requiresRef.get(y).getYdMin().compareTo(laboratoryAsphalt.get(i).getLength2()) < 1 &&
                                requiresRef.get(y).getYdMin().compareTo(laboratoryAsphalt.get(i).getLength3()) < 1) {
                                eligible = 1;
                            } else if (requiresRef.get(y).getYdMin().compareTo(
                                (laboratoryAsphalt.get(i).getLength1().add(laboratoryAsphalt.get(i).getLength2()).add(laboratoryAsphalt.get(i).getLength3())).divide(new BigDecimal(3))
                            ) < 1) {
                                eligible = 1;
                            } else {
                                list.add(bo.getDeptName()+"试验时间："+sdf.format(laboratoryAsphalt.get(i).getCreateTime()) + "，关联延度技术要求不合格，关联的试验类型为：" + bo.getTestType() + "；试验设定温度为：" + laboratoryAsphalt.get(i).getSetTemp() + "；当前温度为："
                                    + laboratoryAsphalt.get(i).getCurrTemp() + "；位移量为：" + laboratoryAsphalt.get(i).getLength1() + "、" + laboratoryAsphalt.get(i).getLength2()
                                    + "、" + laboratoryAsphalt.get(i).getLength3());

                                //发送预警信息
                                String content = bo.getDeptName()+"试验时间："+sdf.format(laboratoryAsphalt.get(i).getCreateTime()) + "，关联延度技术要求不合格，关联的试验类型为：" + bo.getTestType() + "；试验设定温度为：" + laboratoryAsphalt.get(i).getSetTemp() + "；当前温度为："
                                    + laboratoryAsphalt.get(i).getCurrTemp() + "；位移量为：" + laboratoryAsphalt.get(i).getLength1() + "、" + laboratoryAsphalt.get(i).getLength2()
                                    + "、" + laboratoryAsphalt.get(i).getLength3();
                                Integer message = sendTextMessage(content,laboratoryAsphalt.get(i).getDeviceId());
                                if (message == 0) {
                                    boMessage.add("发送成功");
                                } else if (message == 1) {
                                    boMessage.add("发送失败");
                                } else if (message == 2) {
                                    boMessage.add("未选择发送人");
                                }
                            }
                        }
                    }

                }
                laboratoryAsphalt.get(i).setEligible(eligible);
                laboratoryAsphalt.get(i).setRelevance(1);
            }
            bo.setRemarks(list);
            bo.setBoMessage(boMessage);
        elongationResService.updateByBos(laboratoryAsphalt);

    }

    private Integer sendTextMessage(String content, String deviceId) {
        //查询部门id
        String deptId = elongationResService.selectDeptId(deviceId);
        //查询发送手机号
        String warnValLab = "1";
        List<String> receiveAddr = messageService.selectReceiveAddr(deptId,warnValLab);
        Integer message = 2;
        if (receiveAddr.size() > 0) {
             message = usingService.send(receiveAddr, content);
        }

        return message;
    }

    //软化点
    private void estimateRhdQualified(List<NLaboratoryAsphaltRequiresRef> requiresRef, List<NLaboratoryAsphaltSofteningPointRes> softeningPointRes, ZjExperimentBindingBo bo) {
        List<String> list = new ArrayList<>();
        List<String> boMessage = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (int i = 0; i < softeningPointRes.size(); i++) {
            Integer eligible = 0;
            if (requiresRef.get(0).getMin().compareTo(softeningPointRes.get(i).getTemp1()) < 1 &&
                requiresRef.get(0).getMin().compareTo(softeningPointRes.get(i).getTemp2()) < 1) {
                eligible = 1;
            } else {
                list.add(bo.getDeptName()+"试验时间："+sdf.format(softeningPointRes.get(i).getCreateTime()) + "，关联软化点技术要求不合格，关联的试验类型为：" + bo.getTestType() + "；软化点温度为：" +
                    softeningPointRes.get(i).getTemp1() + "、" + softeningPointRes.get(i).getTemp2());
                //发送预警信息
                String content = bo.getDeptName()+"试验时间："+sdf.format(softeningPointRes.get(i).getCreateTime()) + "，关联软化点技术要求不合格，关联的试验类型为：" + bo.getTestType() + "；软化点温度为：" +
                    softeningPointRes.get(i).getTemp1() + "、" + softeningPointRes.get(i).getTemp2();
                Integer message = sendRHDMessage(content,softeningPointRes.get(i).getDeviceId());
                if (message == 0) {
                    boMessage.add("发送成功");
                } else if (message == 1) {
                    boMessage.add("发送失败");
                }else if (message == 2) {
                    boMessage.add("未选择发送人");
                }
            }
            softeningPointRes.get(i).setEligible(eligible);
            softeningPointRes.get(i).setRelevance(1);
        }
        bo.setRemarks(list);
        bo.setBoMessage(boMessage);
        softeningPointResService.updateByBos(softeningPointRes);
    }

    private Integer sendRHDMessage(String content, String deviceId) {
        //查询部门id
        String deptId = softeningPointResService.selectDeptId(deviceId);
        //查询发送手机号
        String warnValLab = "1";
        List<String> receiveAddr = messageService.selectReceiveAddr(deptId, warnValLab);
        Integer message = 2;
        if (receiveAddr.size() > 0) {
            message = usingService.send(receiveAddr, content);
        }
        return message;
    }

    //针入度
    private void estimateZrdQualified(List<NLaboratoryAsphaltRequiresRef> requiresRef, List<NLaboratoryAsphaltPenetrometerRes> penetrometerRes, ZjExperimentBindingBo bo) {
        List<String> list = new ArrayList<>();
        List<String> boMessage = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (int i = 0; i < penetrometerRes.size(); i++) {
            Integer eligible = 0;
            for (int y = 0; y < requiresRef.size(); y++) {
                if (requiresRef.get(y).getTemperature().compareTo(new BigDecimal(25)) == 0) {
                    if (requiresRef.get(y).getMin().compareTo(penetrometerRes.get(i).getRealTimeDisplacement()) < 1 && penetrometerRes.get(i).getRealTimeDisplacement().compareTo(requiresRef.get(y).getMax()) < 1) {
                        eligible = 1;
                    } else {
                        list.add(bo.getDeptName()+"试验时间："+sdf.format(penetrometerRes.get(i).getCreateTime()) + "，关联针入度技术要求不合格，关联的试验类型为：" + bo.getTestType()+"；针入度位移为："+penetrometerRes.get(i).getRealTimeDisplacement());
                        //发送预警信息
                        String content = bo.getDeptName()+"试验时间："+sdf.format(penetrometerRes.get(i).getCreateTime()) + "，关联针入度技术要求不合格，关联的试验类型为：" + bo.getTestType()+"；针入度位移为："+penetrometerRes.get(i).getRealTimeDisplacement();
                        Integer message = sendZRDessage(content,penetrometerRes.get(i).getDeviceId());
                        if (message == 0) {
                            boMessage.add("发送成功");
                        } else if (message == 1) {
                            boMessage.add("发送失败");
                        }else if (message == 2) {
                            boMessage.add("未选择发送人");
                        }
                    }
                }
            }
            penetrometerRes.get(i).setEligible(eligible);
            penetrometerRes.get(i).setRelevance(1);
        }
        bo.setRemarks(list);
        bo.setBoMessage(boMessage);
        penetrometerResService.updateByBos(penetrometerRes);
    }

    private Integer sendZRDessage(String content, String deviceId) {
        //查询部门id
        String deptId = penetrometerResService.selectDeptId(deviceId);
        //查询发送手机号
        String warnValLab = "1";
        List<String> receiveAddr = messageService.selectReceiveAddr(deptId, warnValLab);
        Integer message = 2;
        if (receiveAddr.size() > 0) {
            message = usingService.send(receiveAddr, content);
        }
        return message;
    }

    // 选中的实验列表与马歇尔技术要求对比判断是否合格
    private void estimateMarshallQualified(List<NLaboratoryMarshallStabilityNewRes> marshallResList, NLaboratoryMarshallRequires marshallRequires, ZjExperimentBindingBo bo) {
        // 获取技术要求指标
        BigDecimal flowMaxValue = marshallRequires.getFlowMaxValue(); // 流值上限
        BigDecimal flowMinValue = marshallRequires.getFlowMinValue(); // 流值下限
        BigDecimal stabilityValue = marshallRequires.getStabilityValue(); // 稳定值
        List<String> list = new ArrayList<>();
        // 遍历实验数据列表,与选择的技术要求对比,在业务表中标记是否合格是否关联,在关联表中备注不合格信息
        for (NLaboratoryMarshallStabilityNewRes entity: marshallResList) {
            // 稳定值,流值不为空时,判断是否等于指标值
            if (ObjectUtils.isNotEmpty(entity.getWd()) && ObjectUtils.isNotEmpty(entity.getFlux()) && entity.getWd().compareTo(stabilityValue) == 0) {
                if (entity.getFlux().compareTo(flowMinValue) == -1 && entity.getFlux().compareTo(flowMaxValue) == 1) { // > 下限 < 上限
                    // 合格
                    entity.setEligible(1);
                } else if (entity.getFlux().compareTo(flowMaxValue) == 0 || entity.getFlux().compareTo(flowMinValue) == -1) { // =上下限
                    // 合格
                    entity.setEligible(1);
                } else {
                    // 不合格
                    entity.setEligible(0);
                }
            } else {
                // 不合格
                entity.setEligible(0);
                list.add(bo.getDeptName() + "关联的马歇尔试验数据不合格：试验类型为：" + bo.getTestType()+"；试验数据稳定值为："+entity.getWd()+"，试验数据流值为："+entity.getFlux()+"；");
            }
            // 已关联
            entity.setRelevance(1);
        }
        bo.setRemarks(list);
        // 批量更新业试验数据列表
        inLaboratoryMarshallStabilityNewResService.updateBatch(marshallResList);
    }

    //获取针入度、软化点技术要求
    private List<NLaboratoryAsphaltRequiresRef> getRequiresRef(String testType, String type) {
        return requiresRefService.selectRequiresRef(testType,type);
    }
    //获取延度技术要求
    private List<NLaboratoryAsphaltRequiresRef> getRequiresRefYd(String testType, String type) {
        return requiresRefService.getRequiresRefYd(testType, type);
    }
    // 获取马歇尔技术要求
    public NLaboratoryMarshallRequires getMarshallRequires(ZjExperimentBindingBo bo) {
        return inLaboratoryMarshallRequiresService.getMarshallRequires(bo);
    }

    /**
     * 修改试验数据绑定
     */
    @Override
    public Boolean updateByBo(ZjExperimentBindingBo bo) {
        ZjExperimentBinding update = BeanUtil.toBean(bo, ZjExperimentBinding.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(ZjExperimentBinding entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除试验数据绑定
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 已关联试验数据分页
     *
     * @param bo
     * @param pageQuery
     * @return
     */
    @Override
    public TableDataInfo<Map<String, Object>> page(ZjExperimentBindingBo bo, PageQuery pageQuery) {
        Page<Map<String, Object>> result = null;
        //判断关联的试验数据类型，校验是否合格 1延度 2软化点 3针入度 4燃烧炉 5马歇尔
        if (bo.getType() == 1) {
            result = elongationResService.selectYdPage(bo, pageQuery.build());
        } else if (bo.getType() == 2) {
            result = softeningPointResService.selectRhdPage(bo, pageQuery.build());
        } else if (bo.getType() == 3) {
            result = penetrometerResService.selectZrdPage(bo, pageQuery.build());
        } else if (bo.getType() == 4) {
            result = inLaboratoryAsphaltCombustionFurnaceResService.getRelPage(pageQuery.build(), bo);
        } else if (bo.getType() == 5) {
            result = inLaboratoryMarshallStabilityNewResService.getRelPage(pageQuery.build(), bo);
        }
        return TableDataInfo.build(result);
    }

    /**
     * 取消关联
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancel(String id) {
        ZjExperimentBinding binding = baseMapper.selectById(id);
        Integer eligible = null;
        Integer relevance = 0;
        //1延度 2软化点 3针入度 4燃烧炉 5马歇尔
        if (binding.getType() == 1) {
            elongationResService.updateStatus(binding.getLaboratoryId(),eligible,relevance);
        } else if (binding.getType() == 2) {
            softeningPointResService.updateStatus(binding.getLaboratoryId(),eligible,relevance);
        } else if (binding.getType() == 3) {
            penetrometerResService.updateStatus(binding.getLaboratoryId(),eligible,relevance);
        } else if (binding.getType() == 4) {
            inLaboratoryAsphaltCombustionFurnaceResService.updateStatus(binding.getLaboratoryId(),eligible,relevance);
        } else if (binding.getType() == 5) {
            inLaboratoryMarshallStabilityNewResService.updateStatus(binding.getLaboratoryId(),eligible,relevance);
        }

        baseMapper.deleteById(id);
    }
}
